package com.example.registerstarter;

import com.alibaba.fastjson.JSONObject;
import com.example.registerapi.RegisterInfo;
import com.example.registerapi.RegisterInfoHolder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;

/**
 * @author：kangxuan
 * @date：2024/9/30 10:18 AM
 * @desc:
 */
@RestController
public class RegisterManageController implements BeanFactoryAware {

    private BeanFactory beanFactory;

    /**
     * 服务上线回调
     * @param name
     * @param ip
     * @param port
     * @return
     */
    @GetMapping("/serverOnline")
    public String notify(String name,String ip,String port) {
        RegisterInfoHolder.register(name,ip,port);
        return "ok";
    }

    /**
     * 服务下线回调
     * @param name
     * @param ip
     * @param port
     * @return
     */
    @GetMapping("/serverOffline")
    public String serverOffline(String name,String ip,String port) {
        RegisterInfoHolder.remove(name,ip,port);
        return "ok";
    }

    /**
     * 健康检查
     * @return
     */
    @GetMapping("/health")
    public String health() {
        return "ok";
    }

    public static Map<String, Semaphore> METHOD_CALL_LOCK_MAP = new HashMap<>();
    static {
        METHOD_CALL_LOCK_MAP.put("com.example.demoapi.product.ProductService#getList",
                new Semaphore(5));
    }

    /**
     * 服务调用
     * @param className
     * @param methodName
     * @param args
     * @return
     */
    @GetMapping("/serverCall")
    public Object offline(String className,
                          String methodName,
                          String args,
                          @RequestHeader(RegisterInfoHolder.REQ_CHAIN_TAG_NAME) String reqChainTag) {
        try {
            // 记录调用链
            recordReqChain(className, methodName, args, reqChainTag);

            // 处理服务端限流
            Semaphore semaphore = null;
            if (METHOD_CALL_LOCK_MAP.containsKey(className + "#" + methodName)) {
                List<RegisterInfo> registerInfos = RegisterInfoHolder.getRegisterInfos(className);
                semaphore = METHOD_CALL_LOCK_MAP.get(className + "#" + methodName);
                semaphore.acquire();
            }

            Class<?> aClass = Class.forName(className);
            // 类
            Object bean = this.beanFactory.getBean(aClass);

            // 参数处理
            Object retVal = null;
            // ----无参数
            JSONObject jsonObject = JSONObject.parseObject(URLDecoder.decode(args, "UTF-8"));
            if (jsonObject.isEmpty()) {
                // 方法
                Method declaredMethod = aClass.getDeclaredMethod(methodName);
                retVal = declaredMethod.invoke(bean);
            } else {
                //  ---多参数
                int size = jsonObject.size();
                Object[] params = new Object[size];
                Class<?>[] parameterTypes = new Class<?>[size];
                for (int i = 0; i < size; i++) {
                    JSONObject temp = jsonObject.getJSONObject(i + "");
                    String type = temp.getString("className");
                    parameterTypes[i] = Class.forName(type);
                    if (temp.getBoolean("isNull")) {
                        params[i] = null;
                    } else {
                        params[i] = temp.getObject("value", Class.forName(type));
                    }
                }
                // 方法
                Method declaredMethod = aClass.getDeclaredMethod(methodName, parameterTypes);

                retVal = declaredMethod.invoke(bean, params);
            }
            if (semaphore != null) {
                semaphore.release();
            }
            return retVal;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void recordReqChain(String className, String methodName, String args, String reqChainTag) {
        RegisterInfoHolder.setReqChainTag(reqChainTag);
        System.out.println("reqChainTag:"+reqChainTag + ",接收到请求:" + methodName);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}
